package com.fy.market.persistent.redis;

import cn.hutool.log.Log;
import com.fy.market.types.common.constant.KeysConstant;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.*;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * Redis 服务 - Redisson
 *
 * @author fwq
 * @date 2025-09-26
 */
@Slf4j
@Service("redissonService")
public class RedissonService implements IRedisService {

    @Resource
    private RedissonClient redissonClient;

    /**
     * 设置值 不设置过期时间
     *
     * @param key   键
     * @param value 值
     * @param <T>   泛型
     */
    public <T> void setValue(String key, T value) {
        redissonClient.<T>getBucket(key).set(value);
    }

    /**
     * 设置值 设置过期时间
     *
     * @param key     键
     * @param value   值
     * @param expired 过期时间
     * @param <T>     泛型
     */
    @Override
    public <T> void setValue(String key, T value, long expired) {
        RBucket<T> bucket = redissonClient.getBucket(key);
        bucket.set(value, Duration.ofMillis(expired));
    }

    /**
     * 获取值
     *
     * @param key 键
     * @param <T> 泛型
     * @return 值
     */
    public <T> T getValue(String key) {
        return redissonClient.<T>getBucket(key).get();
    }

    /**
     * 获取队列
     *
     * @param key 键
     * @param <T> 泛型
     * @return 队列
     */
    @Override
    public <T> RQueue<T> getQueue(String key) {
        return redissonClient.getQueue(key);
    }

    /**
     * 获取阻塞队列
     *
     * @param key 键
     * @param <T> 泛型
     * @return 阻塞队列
     */
    @Override
    public <T> RBlockingQueue<T> getBlockingQueue(String key) {
        return redissonClient.getBlockingQueue(key);
    }

    /**
     * 获取延迟队列
     *
     * @param rBlockingQueue 阻塞队列
     * @param <T>            泛型
     * @return 延迟队列
     */
    @Override
    public <T> RDelayedQueue<T> getDelayedQueue(RBlockingQueue<T> rBlockingQueue) {
        return redissonClient.getDelayedQueue(rBlockingQueue);
    }

    /**
     * 设置原子长整型
     *
     * @param key   键
     * @param value 值
     */
    @Override
    public void setAtomicLong(String key, long value) {
        redissonClient.getAtomicLong(key).set(value);
    }

    /**
     * 获取原子长整型
     *
     * @param key 键
     * @return 原子长整型
     */
    @Override
    public long getAtomicLong(String key) {
        return redissonClient.getAtomicLong(key).get();
    }

    /**
     * 增加
     *
     * @param key 键
     * @return 增加后的值
     */
    @Override
    public long incr(String key) {
        return redissonClient.getAtomicLong(key).incrementAndGet();
    }

    /**
     * 增加
     *
     * @param key   键
     * @param delta 增量
     * @return 增加后的值
     */
    @Override
    public long incrBy(String key, long delta) {
        return redissonClient.getAtomicLong(key).addAndGet(delta);
    }

    /**
     * 减少
     *
     * @param key 键
     * @return 减少后的值
     */
    @Override
    public long decr(String key) {
        return redissonClient.getAtomicLong(key).decrementAndGet();
    }

    /**
     * 减少
     *
     * @param key   键
     * @param delta 减量
     * @return 减少后的值
     */
    @Override
    public long decrBy(String key, long delta) {
        return redissonClient.getAtomicLong(key).addAndGet(-delta);
    }

    /**
     * 删除
     *
     * @param key 键
     */
    @Override
    public void remove(String key) {
        redissonClient.getBucket(key).delete();
    }

    /**
     * 判断是否存在
     *
     * @param key 键
     * @return 是否存在
     */
    @Override
    public boolean isExists(String key) {
        return redissonClient.getBucket(key).isExists();
    }

    /**
     * 添加到集合
     *
     * @param key   键
     * @param value 值
     */
    public void addToSet(String key, String value) {
        RSet<String> set = redissonClient.getSet(key);
        set.add(value);
    }

    /**
     * 判断是否是集合的成员
     *
     * @param key   键
     * @param value 值
     * @return 是否是集合的成员
     */
    public boolean isSetMember(String key, String value) {
        RSet<String> set = redissonClient.getSet(key);
        return set.contains(value);
    }

    /**
     * 添加到列表
     *
     * @param key   键
     * @param value 值
     */
    public void addToList(String key, String value) {
        RList<String> list = redissonClient.getList(key);
        list.add(value);
    }

    /**
     * 从列表中获取
     *
     * @param key   键
     * @param index 索引
     * @return 值
     */
    public String getFromList(String key, int index) {
        RList<String> list = redissonClient.getList(key);
        return list.get(index);
    }

    /**
     * 获取Map
     *
     * @param key 键
     * @param <K> 键的类型
     * @param <V> 值的类型
     * @return Map
     */
    @Override
    public <K, V> RMap<K, V> getMap(String key) {
        return redissonClient.getMap(key);
    }

    /**
     * 添加到Map
     *
     * @param key   键
     * @param field 字段
     * @param value 值
     */
    public void addToMap(String key, Integer field, Integer value) {
        RMap<Integer, Integer> map = redissonClient.getMap(key);
        map.put(field, value);
    }

    /**
     * 从Map中获取
     *
     * @param key   键
     * @param field 字段
     * @return 值
     */
    public Integer getFromMap(String key, String field) {
        RMap<String, Integer> map = redissonClient.getMap(key);
        return map.get(field);
    }

    /**
     * 从Map中获取
     *
     * @param key   键
     * @param field 字段
     * @param <K>   键的类型
     * @param <V>   值的类型
     * @return 值
     */
    @Override
    public <K, V> V getFromMap(String key, K field) {
        return redissonClient.<K, V>getMap(key).get(field);
    }

    /**
     * 添加到有序集合
     *
     * @param key   键
     * @param value 值
     */
    public void addToSortedSet(String key, String value) {
        RSortedSet<String> sortedSet = redissonClient.getSortedSet(key);
        sortedSet.add(value);
    }

    /**
     * 获取锁
     *
     * @param key 键
     * @return 锁
     */
    @Override
    public RLock getLock(String key) {
        return redissonClient.getLock(key);
    }

    /**
     * 获取公平锁
     *
     * @param key 键
     * @return 公平锁
     */
    @Override
    public RLock getFairLock(String key) {
        return redissonClient.getFairLock(key);
    }

    /**
     * 获取读写锁
     *
     * @param key 键
     * @return 读写锁
     */
    @Override
    public RReadWriteLock getReadWriteLock(String key) {
        return redissonClient.getReadWriteLock(key);
    }

    /**
     * 获取信号量
     *
     * @param key 键
     * @return 信号量
     */
    @Override
    public RSemaphore getSemaphore(String key) {
        return redissonClient.getSemaphore(key);
    }

    /**
     * 获取可过期信号量
     *
     * @param key 键
     * @return 可过期信号量
     */
    @Override
    public RPermitExpirableSemaphore getPermitExpirableSemaphore(String key) {
        return redissonClient.getPermitExpirableSemaphore(key);
    }

    /**
     * 获取倒计时锁
     *
     * @param key 键
     * @return 倒计时锁
     */
    @Override
    public RCountDownLatch getCountDownLatch(String key) {
        return redissonClient.getCountDownLatch(key);
    }

    /**
     * 获取布隆过滤器
     *
     * @param key 键
     * @param <T> 泛型
     * @return 布隆过滤器
     */
    @Override
    public <T> RBloomFilter<T> getBloomFilter(String key) {
        return redissonClient.getBloomFilter(key);
    }

    /**
     * 设置NX
     *
     * @param key 键
     * @return 是否设置成功
     */
    @Override
    public Boolean setNx(String key) {
        return redissonClient.getBucket(key).trySet("lock");
    }

    /**
     * 执行Lua脚本
     *
     * @param script Lua脚本内容
     * @param keys   键列表
     * @param args   参数列表
     * @return 执行结果
     */
    @Override
    public List<Object> eval(String script, List<String> keys, List<String> args) {
        return redissonClient.getScript().eval(
                RScript.Mode.READ_WRITE,
                script,
                RScript.ReturnType.MULTI,
                Collections.singletonList(keys),
                args.toArray()
        );
    }

    /**
     * 扣减库存
     * 使用Lua脚本扣减库存，key固定为"stock"
     *
     * @param awardId 奖品ID
     * @return 扣减结果 [错误码, 剩余库存, 消息]
     */
    @Override
    public List<Object> deductStock(Integer strategyId, Integer awardId) {
        // 1. 构建库存键（确保与存储时一致）
        String stockKey = KeysConstant.RedisKey.STRATEGY_AWARD_STOCK + strategyId;

        // 2. 读取Lua脚本文件
        String luaScript = readLuaScript("stock_deduct.lua");

        // 3. 执行Lua脚本
        List<Object> result = redissonClient.getScript().eval(
                RScript.Mode.READ_WRITE,
                luaScript,
                RScript.ReturnType.MULTI,
                Collections.singletonList(stockKey), // KEYS[1] = 库存键
                awardId
        );

        log.info("扣减库存结果: {}", result);
        return result;
    }


    /**
     * 读取Lua脚本文件
     *
     * @param scriptPath 脚本路径
     * @return 脚本内容
     */
    private String readLuaScript(String scriptPath) {
        try {
            ClassPathResource resource = new ClassPathResource(scriptPath);
            return new String(resource.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("读取Lua脚本失败: " + scriptPath, e);
        }
    }

}
